/*
See LICENSE for more info
----------------------------------

Author: Neel Gala, Babu PS
Email id: neelgala@gmail.com
Details: SPI Cluster as master connected to SoC
This invokes multiple slave SPI

-----------------------------------
*/
package spi_cluster;
  import apb              :: *;
  import spi              :: *;
  import DCBus            :: *;
  import Connectable      :: *;

 `include "Soc_map.bsv"

  function Bit#(TLog#(`SPICluster_Num_Slaves)) fn_slave_map (Bit#(`paddr) addr);
    Bool slave_exist = True;
    Bit#(TLog#(`SPICluster_Num_Slaves)) slave_num = 0;
    if(     addr>= `SPI0Base && addr<= `SPI0End )
      slave_num =  `SPI0_slave_num;
    else if(addr>= `SPI1Base && addr<= `SPI1End )
      slave_num =  `SPI1_slave_num;
    else if(addr>= `SPI2Base && addr<= `SPI2End )
      slave_num =  `SPI2_slave_num;
    else
      slave_num = `SPICluster_err_slave_num;

    return slave_num;
  endfunction:fn_slave_map

  interface Ifc_spi_cluster;
    interface SPI_IO#(1) spi0_io;
    interface SPI_IO#(2) spi1_io;
    interface SPI_IO#(1) spi2_io;
    (*always_ready, always_enabled*)
    method Bit#(3) spi_sb_interrupt;
    interface Ifc_apb_slave#(`paddr, 32, 0) slave;
  endinterface

  (*synthesize*)
  module mkspi0(Ifc_spi_apb#(`paddr, 32, `User, 1, 20));
    let clk <- exposeCurrentClock;
    let rst <- exposeCurrentReset;
    let ifc();
    mkspi_apb#(`SPI0Base, clk, rst) _temp(ifc);
    return ifc;
  endmodule:mkspi0
  (*synthesize*)
  module mkspi1(Ifc_spi_apb#(`paddr, 32, `User, 2, 20));
    let clk <- exposeCurrentClock;
    let rst <- exposeCurrentReset;
    let ifc();
    mkspi_apb#(`SPI1Base, clk, rst) _temp(ifc);
    return ifc;
  endmodule:mkspi1
  (*synthesize*)
  module mkspi2(Ifc_spi_apb#(`paddr, 32, `User, 1, 20));
    let clk <- exposeCurrentClock;
    let rst <- exposeCurrentReset;
    let ifc();
    mkspi_apb#(`SPI2Base, clk, rst) _temp(ifc);
    return ifc;
  endmodule:mkspi2

  (*synthesize*)
  module mkspi_cluster(Ifc_spi_cluster);
    let curr_clk<- exposeCurrentClock;
    let curr_reset <- exposeCurrentReset;

    Ifc_apb_master_xactor #(`paddr, 32, 0) c2m_xactor <- mkapb_master_xactor;
    Ifc_apb_slave_xactor #(`paddr, 32, 0)  c2s_xactor <- mkapb_slave_xactor;

    Ifc_apb_fabric #(`paddr, 32,0, `SPICluster_Num_Slaves) fabric <- mkapb_fabric(fn_slave_map);

    let spi0 <- mkspi0();
    let spi1 <- mkspi1();
    let spi2 <- mkspi2();
    Ifc_apb_slave#(`paddr, 32, 0 ) err_slave <- mkapb_err;

    mkConnection(c2m_xactor.apb_side, fabric.frm_master);

    mkConnection(c2s_xactor.fifo_side.i_response,c2m_xactor.fifo_side.o_response);
    mkConnection(c2s_xactor.fifo_side.o_request, c2m_xactor.fifo_side.i_request );

    mkConnection (fabric.v_to_slaves [`SPI0_slave_num ],spi0.slave);
    mkConnection (fabric.v_to_slaves [`SPI1_slave_num ],spi1.slave);
    mkConnection (fabric.v_to_slaves [`SPI2_slave_num ],spi2.slave);
    mkConnection (fabric.v_to_slaves [`SPICluster_err_slave_num ] , err_slave);

    Bit#(3) sb_int;
    sb_int[0] = spi0.device.sb_interrupt;
    sb_int[1] = spi1.device.sb_interrupt;
    sb_int[2] = spi2.device.sb_interrupt;

    interface spi0_io  = spi0.device.io;
    interface spi1_io  = spi1.device.io;
    interface spi2_io  = spi2.device.io;

    method spi_sb_interrupt= sb_int;

    interface slave= c2s_xactor.apb_side;
  endmodule
endpackage

